using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text.RegularExpressions;
using System.Text;
using System.Linq;
using System.Data.Linq.Mapping;

namespace ClubWebsite
{
    public partial class ClubSettings : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // Disable all validators because they will be called manually
            // They need to be disabled because the page automatically
            // validates all validators when a autopostback is done - argh!
            foreach (IValidator validator in Validators)
            {
                ((BaseValidator)validator).Enabled = false;
            }

            // Get the club ID
            Guid clubID = ((Default)Master).ClubID;

            using (MainDataClassesDataContext databaseDataContext = Functions.GetDatabaseDataContext())
            {
                // Only allow access to this page if the user has permission to access it
                if (!Functions.UserHasPermissionToEditSection(Functions.SectionType.Club, clubID))
                {
                        string pageUniqueTextForURLs = databaseDataContext
                            .DBClubs
                            .Where(c => c.ID == clubID)
                            .Select(c => c.DBPage.UniqueTextForURLs)
                            .Single();
                        Response.Redirect(String.Format("../{0}/", pageUniqueTextForURLs));
                }

                // Display the current settings
                if (!IsPostBack)
                {
                    DBClub club = databaseDataContext
                        .DBClubs
                        .Single(c => c.ID == clubID);
                    litClubName.Text = HttpUtility.HtmlEncode(club.Name);
                    txtClubName.Text = club.Name;
                    if (club.DescriptionForSearchEngines != null)
                    {
                        txtDescriptionForSearchEngines.Text = club.DescriptionForSearchEngines;
                    }
                    if (club.KeywordsForSearchEngines != null)
                    {
                        txtKeywordsForSearchEngines.Text = club.KeywordsForSearchEngines;
                    }

                    // Menu items
                    MatchCollection menuGroups = Regex.Matches(club.TemplateHTML, @"(?<=\<div\sid=""clubmenu\w*""\>).*?(?=\</div\>)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
                    int groupCount = 0;
                    foreach(Match menuGroup in menuGroups)
                    {
                        // Only allow the first group until multiple gorups is catered for
                        if (groupCount == 0)
                        {
                            MatchCollection menuItems = Regex.Matches(menuGroup.Value, @"\[listitem]\[page=.*?\](?<Text>.+?)\[/page\]\[/listitem\]", RegexOptions.IgnoreCase);
                            foreach (Match menuItem in menuItems)
                            {
                                // Don't display the home item
                                Guid pageID = new Guid(Regex.Match(menuItem.Value, @"(?<=\[page=).+?(?=\])", RegexOptions.IgnoreCase).Value);
                                if (pageID != club.DefaultPageID)
                                {
                                    lstMenuItems.Items.Add(new ListItem(HttpUtility.HtmlDecode(menuItem.Groups["Text"].Value), menuItem.Value));
                                }
                            }
                        }
                        groupCount++;
                    }

                    // Authorised users
                    lstAuthorisedUsers.Items.Clear();
                    var userProperties = databaseDataContext
                        .Users
                        .Join(databaseDataContext.UsersClubs, u => u.ID, uc => uc.UserID, (u, uc) => new { User = u, ClubID = uc.ClubID })
                        .Where(r => r.ClubID == clubID)
                        .Select(r => new { r.User.Email, r.User.ID });
                    foreach (var user in userProperties)
                    {
                        lstAuthorisedUsers.Items.Add(new ListItem(user.Email, user.ID.ToString()));
                    }
                }
            }
        }

        protected void btnCancel_Click(object sender, EventArgs e)
        {
            // Go to the default page for the club
            using (MainDataClassesDataContext databaseDataContext = Functions.GetDatabaseDataContext())
            {
                string pageUniqueTextForURLs = databaseDataContext
                    .DBClubs
                    .Where(c => c.ID == ((Default)Master).ClubID)
                    .Select(c => c.DBPage.UniqueTextForURLs)
                    .Single();
                Response.Redirect(String.Format("../{0}/", pageUniqueTextForURLs));
            }
        }

        protected void btnOK_Click(object sender, EventArgs e)
        {
            // Validation
            valClubName.Enabled = true;
            valClubName.Validate();
            valDescriptionForSearchEngines.Enabled = true;
            valDescriptionForSearchEngines.Validate();
            valKeywordsForSearchEngines.Enabled = true;
            valKeywordsForSearchEngines.Validate();
            if ((!valClubName.IsValid)
                || (!valDescriptionForSearchEngines.IsValid)
                || (!valKeywordsForSearchEngines.IsValid))
            {
                return;
            }

            // Save the changes
            using (MainDataClassesDataContext databaseDataContext = Functions.GetDatabaseDataContext())
            {
                DBClub club = databaseDataContext
                    .DBClubs
                    .Single(c => c.ID == ((Default)Master).ClubID);
                club.Name = txtClubName.Text.Trim();
                if (txtDescriptionForSearchEngines.Text.Trim().Length > 0)
                {
                    club.DescriptionForSearchEngines = txtDescriptionForSearchEngines.Text.Trim();
                }
                else
                {
                    club.DescriptionForSearchEngines = null;
                }
                if (txtKeywordsForSearchEngines.Text.Trim().Length > 0)
                {
                    club.KeywordsForSearchEngines = txtKeywordsForSearchEngines.Text.Trim();
                }
                else
                {
                    club.KeywordsForSearchEngines = null;
                }

                // Save changes to the menu items
                string menuItemWhiteSpace = Regex.Match(club.TemplateHTML, @"(?<=\[/listitem\])\s*(?=\[listitem\]\[addmenuitem\])", RegexOptions.IgnoreCase).Value;
                StringBuilder menuItems = new StringBuilder();
                foreach (ListItem listItem in lstMenuItems.Items)
                {
                    menuItems.Append(menuItemWhiteSpace + listItem.Value);
                }
                club.TemplateHTML = Regex.Replace(club.TemplateHTML, @"(?<=\[listitem\]\[page=" + club.DefaultPageID + @"\].*?\[/page\]\[/listitem\]).+?(?=\[listitem\]\[addmenuitem\])", menuItems.ToString() + menuItemWhiteSpace, RegexOptions.IgnoreCase | RegexOptions.Singleline);

                // Save changes to the authorised users
                IEnumerable<UsersClub> usersClubs = databaseDataContext
                    .UsersClubs
                    .Where(uc => uc.ClubID == club.ID);
                foreach (ListItem listItem in lstAuthorisedUsers.Items)
                {
                    // Check if the user is not currently authorised
                    Guid userID = new Guid(listItem.Value);
                    if (!usersClubs.Any(uc => uc.UserID == userID))
                    {
                        UsersClub usersClub = new UsersClub();
                        usersClub.UserID = userID;
                        usersClub.ClubID = club.ID;
                        databaseDataContext.UsersClubs.InsertOnSubmit(usersClub);
                    }
                }

                // Remove any users who were removed from the list
                IEnumerable<Guid> userIDsInList = lstAuthorisedUsers.Items
                    .Cast<ListItem>()
                    .Select(li => new Guid(li.Value));
                var unauthorisedUsers = usersClubs
                    .Where(uc => !userIDsInList.Contains(uc.UserID));
                databaseDataContext.UsersClubs.DeleteAllOnSubmit(unauthorisedUsers);

                // Save the changes to the database
                databaseDataContext.SubmitChanges();
            }

            // Refresh the page
            Response.Redirect(Request.RawUrl.ToString());
        }

        protected void valClubName_ServerValidate(object source, ServerValidateEventArgs args)
        {
            // Required
            if (txtClubName.Text.Trim().Length == 0)
            {
                valClubName.ErrorMessage = "An entry is required";
                args.IsValid = false;
                return;
            }

            // Max length
            int maxLength = typeof(DBClub).GetProperties()
                .Where(p => p.Name.ToLower() == "name")
                .Select(p => Functions.GetColumnSize((ColumnAttribute)p.GetCustomAttributes(typeof(ColumnAttribute), false).First()))
                .First();
            if (txtClubName.Text.Trim().Length > maxLength)
            {
                valClubName.ErrorMessage = String.Format("The entry cannot be more than {0} characters", maxLength);
                args.IsValid = false;
                return;
            }

            // Unique
            bool nameInUse = Functions.GetDatabaseDataContext()
                .DBClubs
                .Any(c => (c.Name.ToLower() == txtClubName.Text.ToLower()) && (c.ID != ((Default)Master).ClubID));
            if (nameInUse)
            {
                valClubName.ErrorMessage = "This name is already taken";
                args.IsValid = false;
                return;
            }
        }

        protected void valDescriptionForSearchEngines_ServerValidate(object source, ServerValidateEventArgs args)
        {
            // Max length
            int maxLength = typeof(DBClub).GetProperties()
                .Where(p => p.Name.ToLower() == "descriptionforsearchengines")
                .Select(p => Functions.GetColumnSize((ColumnAttribute)p.GetCustomAttributes(typeof(ColumnAttribute), false).First()))
                .First();
            if (txtDescriptionForSearchEngines.Text.Trim().Length > maxLength)
            {
                valDescriptionForSearchEngines.ErrorMessage = String.Format("The entry cannot be more than {0} characters", maxLength);
                args.IsValid = false;
                return;
            }
        }

        protected void valKeywordsForSearchEngines_ServerValidate(object source, ServerValidateEventArgs args)
        {
            // Max length
            int maxLength = typeof(DBClub).GetProperties()
                .Where(p => p.Name.ToLower() == "keywordsforsearchengines")
                .Select(p => Functions.GetColumnSize((ColumnAttribute)p.GetCustomAttributes(typeof(ColumnAttribute), false).First()))
                .First();
            if (txtKeywordsForSearchEngines.Text.Trim().Length > maxLength)
            {
                valKeywordsForSearchEngines.ErrorMessage = String.Format("The entry cannot be more than {0} characters", maxLength);
                args.IsValid = false;
                return;
            }
        }

        protected void valAuthorisedUsers_ServerValidate(object source, ServerValidateEventArgs args)
        {
            // Selected
            if (lstAuthorisedUsers.SelectedValue.Length == 0)
            {
                valAuthorisedUsers.ErrorMessage = "Select a user to remove";
                args.IsValid = false;
                return;
            }

            // Self
            if (lstAuthorisedUsers.SelectedValue == HttpContext.Current.User.Identity.Name)
            {
                valAuthorisedUsers.ErrorMessage = "You cannot remove yourself";
                args.IsValid = false;
                return;
            }
        }

        protected void valAddAuthorisedUser_ServerValidate(object source, ServerValidateEventArgs args)
        {
            // Required
            if (txtAddAuthorisedUser.Text.Trim().Length == 0)
            {
                valAddAuthorisedUser.ErrorMessage = "An entry is required";
                args.IsValid = false;
                return;
            }

            // Max length
            int maxLength = typeof(User).GetProperties()
                .Where(p => p.Name.ToLower() == "email")
                .Select(p => Functions.GetColumnSize((ColumnAttribute)p.GetCustomAttributes(typeof(ColumnAttribute), false).First()))
                .First();
            if (txtAddAuthorisedUser.Text.Trim().Length > maxLength)
            {
                valAddAuthorisedUser.ErrorMessage = String.Format("The entry cannot be more than {0} characters", maxLength);
                args.IsValid = false;
                return;
            }

            // Exists
            Guid userID = Functions.GetDatabaseDataContext()
                .Users
                .Where(u => u.Email.ToLower() == txtAddAuthorisedUser.Text.Trim().ToLower())
                .Select(u => u.ID)
                .FirstOrDefault();
            if (userID == Guid.Empty)
            {
                valAddAuthorisedUser.ErrorMessage = "This user has not registered on this site";
                args.IsValid = false;
                return;
            }

            // Already in list
            foreach (ListItem listItem in lstAuthorisedUsers.Items)
            {
                if (new Guid(listItem.Value) == userID)
                {
                    valAddAuthorisedUser.ErrorMessage = "This user is already in the list";
                    args.IsValid = false;
                    return;
                }
            }
        }

        protected void btnRemoveAuthorisedUser_Click(object sender, EventArgs e)
        {
            // Validation
            valAuthorisedUsers.Enabled = true;
            valAuthorisedUsers.Validate();
            if (!valAuthorisedUsers.IsValid)
            {
                return;
            }

            // Remove the selected user from the list
            lstAuthorisedUsers.Items.Remove(lstAuthorisedUsers.SelectedItem);
        }

        protected void btnAddAuthorisedUser_Click(object sender, EventArgs e)
        {
            // Validation
            valAddAuthorisedUser.Enabled = true;
            valAddAuthorisedUser.Validate();
            if (!valAddAuthorisedUser.IsValid)
            {
                return;
            }

            // Add the user to the list
            var userProperties = Functions.GetDatabaseDataContext()
                .Users
                .Where(u => u.Email.ToLower() == txtAddAuthorisedUser.Text.Trim().ToLower())
                .Select(u => new { u.Email, u.ID })
                .Single();
            lstAuthorisedUsers.Items.Add(new ListItem(userProperties.Email, userProperties.ID.ToString()));

            // Clear the text box
            txtAddAuthorisedUser.Text = "";
        }

        protected void btnAddMenuItem_Click(object sender, EventArgs e)
        {
            // Validation
            valAddMenuItem.Enabled = true;
            valAddMenuItem.Validate();
            if (!valAddMenuItem.IsValid)
            {
                return;
            }

            // Add the menu item to the club
            string line = "[listitem][page=" + Guid.NewGuid() + "]" + HttpUtility.HtmlEncode(txtAddMenuItem.Text) + "[/page][/listitem]";
            lstMenuItems.Items.Add(new ListItem(txtAddMenuItem.Text, line));

            // Clear the text box
            txtAddMenuItem.Text = "";
        }

        protected void valAddMenuItem_ServerValidate(object source, ServerValidateEventArgs args)
        {
            // Required
            if (txtAddMenuItem.Text.Trim().Length == 0)
            {
                valAddMenuItem.ErrorMessage = "An entry is required";
                args.IsValid = false;
                return;
            }

            // Max length
            int maxLength = typeof(DBPage).GetProperties()
                .Where(p => p.Name.ToLower() == "title")
                .Select(p => Functions.GetColumnSize((ColumnAttribute)p.GetCustomAttributes(typeof(ColumnAttribute), false).First()))
                .First();
            if (txtAddMenuItem.Text.Trim().Length > maxLength)
            {
                valAddMenuItem.ErrorMessage = String.Format("The entry cannot be more than {0} characters", maxLength);
                args.IsValid = false;
                return;
            }

            // Unique
            foreach (ListItem listItem in lstMenuItems.Items)
            {
                if (listItem.Text.Trim().ToLower() == txtAddMenuItem.Text.Trim().ToLower())
                {
                    valAddMenuItem.ErrorMessage = "The entry already exists.";
                    args.IsValid = false;
                    return;
                }
            }
        }

        protected void valMenuItems_ServerValidate(object source, ServerValidateEventArgs args)
        {
            // Selected
            if (lstMenuItems.SelectedValue.Length == 0)
            {
                valMenuItems.ErrorMessage = "Select a menu item";
                args.IsValid = false;
                return;
            }
        }

        protected void btnRemoveMenuItem_Click(object sender, EventArgs e)
        {
            // Validation
            valMenuItems.Enabled = true;
            valMenuItems.Validate();
            if (!valMenuItems.IsValid)
            {
                return;
            }

            // Remove the selected menu item from the list
            lstMenuItems.Items.Remove(lstMenuItems.SelectedItem);
        }

        protected void btnMoveMenuItemUp_Click(object sender, EventArgs e)
        {
            // Validation
            valMenuItems.Enabled = true;
            valMenuItems.Validate();
            if (!valMenuItems.IsValid)
            {
                return;
            }

            // Move the selected menu item up the list
            if (lstMenuItems.SelectedIndex > 0)
            {
                lstMenuItems.Items.Insert(lstMenuItems.SelectedIndex + 1, lstMenuItems.Items[lstMenuItems.SelectedIndex - 1]);
                lstMenuItems.Items.RemoveAt(lstMenuItems.SelectedIndex - 1);
            }
        }

        protected void btnMoveMenuItemDown_Click(object sender, EventArgs e)
        {
            // Validation
            valMenuItems.Enabled = true;
            valMenuItems.Validate();
            if (!valMenuItems.IsValid)
            {
                return;
            }

            // Remove the selected menu item down the list
            if (lstMenuItems.SelectedIndex < lstMenuItems.Items.Count - 1)
            {
                lstMenuItems.Items.Insert(lstMenuItems.SelectedIndex, lstMenuItems.Items[lstMenuItems.SelectedIndex + 1]);
                lstMenuItems.Items.RemoveAt(lstMenuItems.SelectedIndex + 1);
            }
        }
    }
}
